package com.ydlclass.channelHandler.handler;

import com.ydlclass.YrpcBootstrap;
import com.ydlclass.compress.Factory.CompressFactory;
import com.ydlclass.serialize.Factory.SerializeFactory;
import com.ydlclass.serialize.SerializeWrapper;
import com.ydlclass.serialize.Serializer;
import com.ydlclass.transport.message.MessageFormatConstant;
import com.ydlclass.transport.message.YrpcRequest;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;

/**
 *  4byte    magic(魔术值)     --> yrpc.getBytes()
 *  1byte    version(版本)     --> 1
 *  2byte    header length 首部的长度
 *  4byte    full  length  报文总长度
 *  1byte    serialize
 *  1byte    compress
 *  1byte    requestType
 *  8byte    requestId
 *
 *  body
 *
 * 出站的时候，第一个经过的处理器
 * @author Knife
 */
@Slf4j
public class YrpcRequestEncoder extends MessageToByteEncoder<YrpcRequest> {
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, YrpcRequest yrpcRequest, ByteBuf byteBuf) throws Exception {
        /**
         * 4个字节的魔术值
         */
        byteBuf.writeBytes(MessageFormatConstant.MAGIC);
        /**
         * 1个字节的版本号
         */
        byteBuf.writeByte(MessageFormatConstant.VERSION);
        /**
         * 2个字节的头部的长度
         */
        byteBuf.writeShort(MessageFormatConstant.HEADER_LENGTH);
        /**
         * todo 总长度现在不清楚，不知道body的长度,空出来
         */
        byteBuf.writerIndex(byteBuf.writerIndex() + MessageFormatConstant.FULL_FIELD_LENGTH);
        /**
         * 3个类型 , 请求，序列化，压缩
         */
        byteBuf.writeByte(yrpcRequest.getSerializeType());
        byteBuf.writeByte(yrpcRequest.getCompressType());
        byteBuf.writeByte(yrpcRequest.getRequestType());
        /**
         * 8字节的请求id
         */
        byteBuf.writeLong(yrpcRequest.getRequestId());
        /**
         * 8字节的时间戳
         */
        byteBuf.writeLong(yrpcRequest.getTimeStamp());

        // todo 如果是心跳请求，就不处理请求体
        //        if (yrpcRequest.getRequestType() == RequestType.HEART_BEAT.getId()){
        //            // 处理一下总长度，其实总长度就是 header长度
        //            // 保存当前的写指针的位置
        //            int writeIndex = byteBuf.writerIndex();
        //            // 将写指针拨到之前的full_length 的位置
        //            byteBuf.writerIndex(MessageFormatConstant.MAGIC.length +
        //                    MessageFormatConstant.VERSION_LENGTH +
        //                    MessageFormatConstant.HEADER_FIELD_LENGTH);
        //            // 写入
        //            byteBuf.writeInt(MessageFormatConstant.HEADER_LENGTH);
        //            // 再将写指针拨回
        //            byteBuf.writerIndex(writeIndex);
        //        }


        /**
         * body  --写入请求体RequestPayload
         */
        // 1、根据配置的序列化方式，将请求体序列化
        // 怎么实现序列化？ 1、工具类，耦合度比较高，以后想要进行替换，就需要修改工具类
        byte[] body = null;
        if (yrpcRequest.getRequestPayload()!= null){
            Serializer serializer = SerializeFactory
                    .getSerializer(yrpcRequest.getSerializeType())
                    .getSerializer();
            body = serializer.serialize(yrpcRequest.getRequestPayload());

            //  2、根据配置的压缩方式，将序列化后的请求体进行压缩
            body = CompressFactory
                    .getCompressor(yrpcRequest.getCompressType())
                    .getCompressor()
                    .compress(body);
        }




        if (body != null){
            byteBuf.writeBytes(body);
        }
        int bodyLength = body == null? 0 : body.length;

        /**
         * 重新处理报文的总长度
         * 1、保存当前的写指针，避免回不去
         * 2、将写指针移动至写总长度的位置上去
         */
         int writeIndex = byteBuf.writerIndex();
         byteBuf.writerIndex(MessageFormatConstant.MAGIC.length +
                 MessageFormatConstant.VERSION_LENGTH +
                 MessageFormatConstant.HEADER_FIELD_LENGTH);
         byteBuf.writeInt(MessageFormatConstant.HEADER_LENGTH + bodyLength);

        /**
         * 写指针归位
         */
        byteBuf.writerIndex(writeIndex);

        if (log.isDebugEnabled()){
            log.debug("RequestEncoder::请求：{}已经完成报文的编码",yrpcRequest.getRequestId());
        }

    }
}
